package com.google.code.b0rx0r.program;

import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;

public class Program implements Serializable, SampleListener {
	
	private static final long serialVersionUID = "Program 1.0".hashCode(); //$NON-NLS-1$

	private String name = "demo"; //$NON-NLS-1$
	private List<Sample> samples = new ArrayList<Sample>();
	private List<Slice> slices = new ArrayList<Slice>();
	private List<Sequence> sequences = new ArrayList<Sequence>();
	
	private transient List<ProgramListener> programListeners = new ArrayList<ProgramListener>();
	private transient ProgramManager pm;
	
	public Program(ProgramManager pm) {
		this.pm = pm;
		
		try {
			addSample(new Sample(new File("C:/Documents and Settings/Lui/My Documents/amen (master).wav"))); //$NON-NLS-1$
//			addSample(new Sample()); //$NON-NLS-1$
		} catch (UnsupportedAudioFileException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (LineUnavailableException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		addSequence( new Sequence(pm));
	}
	
	public List<Sample> getSamples() {
		return Collections.unmodifiableList(samples);
	}
	
	public void addSample(Sample sample) {
		samples.add(sample);
		sample.addSampleObserver(this);
		fireSampleAdded(sample);
	}

	public void remove(Sample sample) {
		samples.remove(sample);
		sample.removeSampleObserver(this);
		fireSampleRemoved(sample);
	}

	public List<Slice> getSlices() {
		return Collections.unmodifiableList(slices);
	}
	
	public void addSequence(Sequence s) {
		sequences.add(s);
//		s.addSequenceObserver(this);
		fireSequenceAdded(s);
	}
	
	public void removeSequence(Sequence s) {
		sequences.remove(s);
//		s.removeSequenceObserver(this);
		fireSequenceRemoved(s);
	}

	public List<Sequence> getSequences() {
		return Collections.unmodifiableList(sequences);
	}


	public void addProgramListener(ProgramListener listener) {
		programListeners.add(listener);
	}

	public void removeProgramListener(ProgramListener listener) {
		programListeners.remove(listener);
	}
	
	public void fireSampleAdded(Sample sample) {
		for (ProgramListener l : programListeners) {
			l.sampleAdded(sample);
		}
	}
	
	public void fireSampleRemoved(Sample sample) {
		for (ProgramListener l : programListeners) {
			l.sampleRemoved(sample);
		}
	}
	
	public void fireSliceAdded(Slice slice) {
		for (ProgramListener l : programListeners) {
			l.sliceAdded(slice);
		}
	}
	
	public void fireSliceRemoved(Slice slice) {
		for (ProgramListener l : programListeners) {
			l.sliceRemoved(slice);
		}
	}
	
	public void fireSequenceAdded(Sequence sequence) {
		for (ProgramListener l : programListeners) {
			l.sequenceAdded(sequence);
		}
	}
	
	public void fireSequenceRemoved(Sequence sequence) {
		for (ProgramListener l : programListeners) {
			l.sequenceRemoved(sequence);
		}
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	
	private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
		in.defaultReadObject();
		programListeners = new ArrayList<ProgramListener>();
	}

	@Override
	public void sliceAdded(Slice sp) {
		slices.add(sp);
		fireSliceAdded(sp);
	}

	@Override
	public void sliceRemoved(Slice sp) {
		slices.remove(sp);
		fireSliceRemoved(sp);
	}

	@Override
	public void sliceMoved(Slice sp) {}


	@Override
	public void snapPointAdded(SnapPoint sp) {}

	@Override
	public void snapPointMoved(SnapPoint sp) {}

	@Override
	public void snapPointRemoved(SnapPoint sp) {}

	public Collection<Sequencable> getSequencablesForMidiNote(int note) {
		Set<Sequencable> retVal = new HashSet<Sequencable>();
		
		for (Slice s : slices) {
			if (s.getNote() == note)
				retVal.add(s);
		}
		
		for (Sequence s : sequences) {
			if (s.getNote() == note)
				retVal.add(s);
		}
		return retVal;
	}

	void setProgramManager(ProgramManager programManager) {
		this.pm = programManager;

		for (Sequence s : sequences) {
			s.setProgramManager(programManager);
		}
		
	}


}
